#pragma once

namespace lim
{
    template<class T>
    struct ListNode
    {
        ListNode(const T& val = T())
        {
            _pPre = nullptr;
            _pNext = nullptr;
            _val = val;
        }
        ListNode<T>* _pPre;
        ListNode<T>* _pNext;
        T _val;
    };


    template<class T, class Ref, class Ptr>
    struct ListIterator
    {
        typedef ListNode<T>* PNode;
        typedef ListIterator<T, Ref, Ptr> Self;
        ListIterator(PNode pNode = nullptr)
            :_pNode(pNode)
        {
        }
        ListIterator(const Self& l)
            :_pNode(l._pNode)
        {
        }
        Ref operator*()
        {
            return _pNode->_val;
        }
        Ptr operator->()
        {
            return &_pNode->_data;
        }
        Self& operator++()
        {
            _pNode = _pNode->_pNext;
            return *this;
        }
        Self operator++(int)
        {
            Self it(*this);
            _pNode = _pNode->_pNext;
            return it;
        }
        Self& operator--()
        {
            _pNode = _pNode->_pPre;
            return *this;
        }
        Self& operator--(int)
        {
            Self it(*this);
            _pNode = _pNode->_pPre;
            return it;
        }
        bool operator!=(const Self& l) 
        {
            return l._pNode != _pNode;
        }
        bool operator==(const Self& l) 
        {
            return l._pNode == _pNode;
        }
        PNode _pNode;
    };

    template<class Iterator, class Ref, class Ptr>
    struct Reverse_iterator
    {

        typedef Reverse_iterator<Iterator, Ref, Ptr> Self;

        Reverse_iterator(Iterator it = nullptr)
            :_it(it)
        {

        }
        Ref operator*()
        {
            Iterator it = _it;
            return *(--it);
        }

        Ptr operator->()
        {

            return _it.operator->();
        }

        Self& operator++ ()
        {
            --_it;
            return *this;
        }

        Self& operator++(int)
        {
            Iterator it = _it;
            --_it;
            return *this;
        }

        Self& operator-- ()
        {
            ++_it;
            return *this;
        }

        Self& operator--(int)
        {
            Iterator it = _it;
            ++_it;
            return *this;
        }
        bool operator==(const Self& it)
        {
            return _it == it;
        }
        bool operator!=(const Self& it)
        {
            return _it != it._it;
        }
        Iterator _it;

    };

    template<class T>
    class list
    {
        typedef ListNode<T> Node;
        typedef Node* PNode;
    public:
        typedef ListIterator<T, T&, T*> iterator;
        typedef ListIterator<T, const T&, const T*> const_iterator;

        typedef Reverse_iterator<iterator, T&, T*> reserve_iterator;
        typedef Reverse_iterator<const_iterator, const T&,const T*> const_reserve_iterator;

    public:

        list()
        {
            CreateHead();


        }
        list(int n, const T& value = T())
        {
            CreateHead();


            for (int i = 0; i < n; i++)
            {
                PNode NNode = new Node(value);
                push_back(value);

            }
        }
        template <class Iterator>
        list(Iterator first, Iterator last)
        {
            CreateHead();

            while (first != last)
            {
                push_back(*first);
                ++first;
            }

        }
        list(const list<T>& l)
        {

            CreateHead();
            for (const_iterator it = l.begin();it !=l.end(); it++)
            {
                push_back(*it);
            }
        }
        list<T>& operator=(const list<T> l)
        {
            list<T> tmp(l);
            swap(tmp);
            return *this;
        }
        ~list()
        {
            PNode tmp = _pHead->_pNext;
            while (tmp != _pHead)
            {
                tmp = tmp->_pNext;
                delete tmp->_pPre;
            }
            delete tmp;
        }


        iterator begin()
        {
            return iterator(_pHead->_pNext);
        }      
        reserve_iterator rbegin()
        {
            return reserve_iterator(end());
        }

        iterator end()
        {
            return iterator(_pHead);
        }
        reserve_iterator rend()
        {
            return reserve_iterator(begin());
        }

        const_iterator begin() const
        {
            return const_iterator(_pHead->_pNext);
        }
        const_reserve_iterator rbegin() const
        {
            return const_reserve_iterator(end());
        }

        const_iterator end() const
        {
            return const_iterator(_pHead);
        }
        const_reserve_iterator rend() const
        {
            return const_reserve_iterator(begin());
        }


  

        size_t size() const
        {
            int size = 0;
            const_iterator it = begin(_pHead);
            while (end(_pHead) != it)
            {
                size++;
                it++;
            }
            return size;
        }
        bool empty() const
        {
            return _pHead == _pHead->_pNext;
        }


        T& front()
        {
            assert(begin() != end());
            return *begin();
        }
        const T& front()const
        {
            assert(begin() != end());
            return *begin();

        }
        T& back()
        {
            assert(begin() != end());
            return *(++end());
        }
        const T& back()const
        {
            assert(begin() != end());
            return *(++end());

        }


        void push_back(const T& val) { insert(end(), val); }
        void pop_back() { erase(--end()); }
        void push_front(const T& val) { insert(begin(), val); }
        void pop_front() { erase(begin()); }
        iterator insert(iterator pos, const T& val)
        {
            PNode tmp = new Node(val);
            tmp->_pNext = pos._pNode;
            tmp->_pPre = pos._pNode->_pPre;
            pos._pNode->_pPre = tmp;
            tmp->_pPre->_pNext = tmp;
            return iterator(tmp);
        }
        iterator erase(iterator pos)
        {
            
            PNode pre = pos._pNode->_pPre;
            PNode next = pos._pNode->_pNext;

            pre->_pNext = next;
            next->_pPre = pre;
            delete pos._pNode;
            return iterator(next);
        }
        void clear()
        {
            list<T> tmp;
            swap(tmp);

        }
        void swap(list<T>& l)
        {
            std::swap(_pHead, l._pHead);
        }




    private:
        void CreateHead()
        {
            _pHead = new Node;
            _pHead->_pNext = _pHead;
            _pHead->_pPre = _pHead;
        }
        PNode _pHead;
    };

    //void print_list(const list<int>& l)
    //{
    //    list<int>::const_iterator cit = l.cbegin();
    //   // cout <<111<< "<-";

    //    while (cit != l.cend())
    //    {

    //        cout << cit._pNode->_val << "<-" ;
    //        //cout << endl;
    //        ++cit;
    //    }
    //    cout << endl;

    //}


}



